package org.fujay.langchain4jserver.domain.conversation.aggregate;

import lombok.Getter;
import lombok.NonNull;
import org.fujay.langchain4jserver.application.dto.MessageDTO;
import org.fujay.langchain4jserver.domain.application.vo.AppId;
import org.fujay.langchain4jserver.domain.conversation.entity.Conversation;
import org.fujay.langchain4jserver.domain.conversation.entity.MessageEntity;
import org.fujay.langchain4jserver.domain.conversation.vo.ConversationId;
import org.fujay.langchain4jserver.domain.conversation.vo.MessageId;
import org.fujay.langchain4jserver.domain.conversation.vo.TokenUsage;
import org.fujay.langchain4jserver.domain.conversation.vo.UserId;

import java.time.LocalDateTime;
import java.util.*;

/**
 * 会话聚合根
 */
@Getter
public class ConversationAggregate {

    @NonNull
    private final Conversation conversation;

    @NonNull
    private final List<MessageEntity> messages;

    // Constructor needs to accept MessageRepository
    private ConversationAggregate(
            Conversation conversation,
            List<MessageEntity> messages) {
        this.conversation = Objects.requireNonNull(conversation);
        this.messages = Objects.requireNonNull(messages);
    }

    // Factory method needs MessageRepository
    public static ConversationAggregate create(
            ConversationId id, UserId userId, AppId appId) {
        Conversation conv = Conversation.create(id, userId, appId);
        return new ConversationAggregate(conv, new ArrayList<>());
    }

    public static ConversationAggregate load(
            Conversation conversation,
            List<MessageEntity> messages) {
        messages.sort(Comparator.comparing(MessageEntity::getTimestamp));
        return new ConversationAggregate(conversation, new ArrayList<>(messages));
    }

    /**添加用户消息*/
    public MessageEntity addUserMessage(MessageDTO messageDTO) {

        if (messages.isEmpty() && messageDTO.getContent() != null) {
            conversation.updateTitle(messageDTO.getContent().substring(0, Math.min(messageDTO.getContent().length(), 50)));
        }

        MessageId newMessageId = MessageId.create();
        MessageEntity userMessage =
                MessageEntity.createUserMessage(
                        newMessageId, messageDTO.getContent(), messageDTO.getImageUrls(), messageDTO.getMetadata());
        this.addMessageToList(userMessage);
        return userMessage;
    }

    public void addAiMessage(String content, TokenUsage usage, Map<String, Object> metadata) {
        MessageId newMessageId = MessageId.create();
        MessageEntity aiMessage =
                MessageEntity.createAiMessage(
                        newMessageId, content, usage, metadata); // Use factory with ID
        this.addMessageToList(aiMessage);
    }

    public void addSystemMessage(String content) {
        Map<String, Object> metadata = null;
        MessageId newMessageId = MessageId.create(); // Generate ID
        MessageEntity systemMessage =
                MessageEntity.createSystemMessage(newMessageId, content, metadata); // Use factory with ID
        this.addMessageToList(systemMessage);
    }

    private void addMessageToList(MessageEntity message) {
        Objects.requireNonNull(message, "Message cannot be null");
        this.messages.add(message);
        markAsModified();
    }

    // --- 聚合根行为 ---

    // 获取用于传递给LLM的消息历史 (可以根据记忆策略进行截断)
    public List<MessageEntity> getChatHistoryForLLM(int maxMessages) {
        int size = messages.size();
        if (size <= maxMessages) {
            return Collections.unmodifiableList(messages);
        }
        // 简单的截断策略：取最新的 maxMessages 条
        return Collections.unmodifiableList(messages.subList(size - maxMessages, size));
    }

    public ConversationId getId() {
        return conversation.getId();
    }

    public UserId getUserId() {
        return conversation.getUserId();
    }

    public AppId getAppId() {
        return conversation.getAppId();
    }

    public String getTitle() {
        return conversation.getTitle();
    }

    public List<MessageEntity> getMessages() {
        return Collections.unmodifiableList(messages);
    }

    // Add method to get a memory ID (e.g., based on conversation ID)
    public String getMemoryId() {
        return "conv_" + getId().value();
    }

    private void markAsModified() {
        this.conversation.touch(); // Call touch here
    }

    // --- Delegated Getters ---
    public LocalDateTime getCreateTime() {
        return conversation.getCreateTime();
    }

    public LocalDateTime getUpdateTime() {
        return conversation.getUpdateTime();
    }
}
